package tmp_GetTypeFromClass;

import java.io.*;

import zclTool.*;
import java.util.*;

//the goal of this method is to get count(t,c), p(t|c), Rank count(t,c) according to c; p(c|t) rank; p(t|c)p(c|t) p(t|-c)
public class GetManyValues {

	static HashMap<String, Integer> cname2id = new HashMap<String, Integer>();
	static HashMap<String, Integer> tname2id = new HashMap<String, Integer>();
	static ArrayList<String> cnames = new ArrayList<String>();
	static ArrayList<String> tnames = new ArrayList<String>();
	static int MAX = 5000;
	static ArrayList<Integer> classid_typeids[] = new ArrayList[MAX];
	static ArrayList<Integer> classid_typecnts[] = new ArrayList[MAX];

	static ArrayList<Double> classid_pt_given_c[] = new ArrayList[MAX];
	static ArrayList<Double> classid_pt_given_not_c[] = new ArrayList[MAX];

	static ArrayList<Double> classid_pc_given_t[] = new ArrayList[MAX];
	static ArrayList<Double> classid_pc_given_t_times_pt_given_c[] = new ArrayList[MAX];
	static ArrayList<Integer> typeid_classids[] = new ArrayList[MAX];
	static ArrayList<Integer> typeid_classcnts[] = new ArrayList[MAX];

	static int sumc[] = new int[MAX]; // count(c)
	static int sumt[] = new int[MAX]; // count(t)
	static double pct[][]; // p(c,t)

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		load(args[0]);
		getSumC();
		getSumt();
		getPc_given_t();
		getPc_given_t_times_pt_given_c();
		getPt_c_AND_pt_not_c();
		printAll(args[1]);
		printRandom(args[2],100);
	}

	public static void load(String file) {
		for (int i = 0; i < MAX; i++) {
			classid_typeids[i] = new ArrayList<Integer>();
			classid_typecnts[i] = new ArrayList<Integer>();
			typeid_classids[i] = new ArrayList<Integer>();
			typeid_classcnts[i] = new ArrayList<Integer>();
			classid_pc_given_t[i] = new ArrayList<Double>();
			classid_pc_given_t_times_pt_given_c[i] = new ArrayList<Double>();
			classid_pt_given_c[i] = new ArrayList<Double>();
			classid_pt_given_not_c[i] = new ArrayList<Double>();
		}
		try {
			DelimitedReader dr = new DelimitedReader(file);
			String[] line;
			int cid = 0, tid = 0;
			while ((line = dr.read()) != null) {
				int c = Integer.parseInt(line[0]);
				String className = line[1];
				String typeName = line[2];
				if (!cname2id.containsKey(className)) {
					cname2id.put(className, cid);
					cnames.add(className);
					cid++;
				}
				if (!tname2id.containsKey(typeName)) {
					tname2id.put(typeName, tid);
					tnames.add(typeName);
					tid++;
				}
				int a = cname2id.get(className);
				int b = tname2id.get(typeName);
				classid_typeids[a].add(b);
				classid_typecnts[a].add(c);
				typeid_classids[b].add(a);
				typeid_classcnts[b].add(c);
			}
			dr.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void getSumC() {
		for (int i = 0; i < MAX; i++) {
			sumc[i] = 0;
			for (int j = 0; j < classid_typeids[i].size(); j++) {
				// int tid = classid_typeids[i].get(j);
				int count = classid_typecnts[i].get(j);
				sumc[i] += count;
			}
		}
	}

	public static void getSumt() {
		for (int i = 0; i < MAX; i++) {
			sumt[i] = 0;
			for (int j = 0; j < typeid_classids[i].size(); j++) {
				// int cid = typeid_classids[i].get(j);
				int count = typeid_classcnts[i].get(j);
				sumt[i] += count;
			}
		}
	}

	// p(c|t) = p(c,t)/p(t)
	public static void getPc_given_t() {
		for (int i = 0; i < cnames.size(); i++) {
			for (int j = 0; j < classid_typeids[i].size(); j++) {
				int tid = classid_typeids[i].get(j);
				int pct = classid_typecnts[i].get(j);
				int sumthere = sumt[tid];
				double pc_given_t = pct * 1.0 / sumthere;
				classid_pc_given_t[i].add(pc_given_t);
			}
		}
	}

	public static void getPc_given_t_times_pt_given_c() {
		for (int i = 0; i < cnames.size(); i++) {
			for (int j = 0; j < classid_typeids[i].size(); j++) {
				int tid = classid_typeids[i].get(j);
				int pct = classid_typecnts[i].get(j);
				int sumthere = sumt[tid];
				int sumchere = sumc[i];
				double a = pct * pct * 1.0 / sumthere / sumchere;
				classid_pc_given_t_times_pt_given_c[i].add(a);
			}
		}
	}

	public static void getPt_c_AND_pt_not_c() {
		// sum pc
		int sumpc = 0;
		for (int i = 0; i < cnames.size(); i++) {
			sumpc += sumc[i];
		}
		for (int i = 0; i < cnames.size(); i++) {
			for (int j = 0; j < classid_typeids[i].size(); j++) {
				int tid = classid_typeids[i].get(j);
				int pct = classid_typecnts[i].get(j);
				double pt_given_c = pct * 1.0 / sumc[i];
				double pt = sumt[tid];
				double pt_given_not_c = (sumt[tid] - pct) * 1.0
						/ (sumpc - sumc[i]);
				classid_pt_given_c[i].add(pt_given_c);
				classid_pt_given_not_c[i].add(pt_given_not_c);
			}
		}
	}

	public static int[] getRank(ArrayList<Double> values) {
		int[] res = new int[values.size()];
		for (int i = 0; i < values.size(); i++) {
			double vi = values.get(i);
			for (int j = 0; j < values.size(); j++) {
				double vj = values.get(j);
				if (vj > vi)
					res[i]++;
			}
		}
		for (int i = 0; i < res.length; i++)
			res[i]++;
		return res;
	}

	public static int[] getRankInt(ArrayList<Integer> values) {
		int[] res = new int[values.size()];
		for (int i = 0; i < values.size(); i++) {
			double vi = values.get(i);
			for (int j = 0; j < values.size(); j++) {
				double vj = values.get(j);
				if (vj > vi)
					res[i]++;
			}
		}
		for (int i = 0; i < res.length; i++)
			res[i]++;
		return res;
	}

	public static void printAll(String file) {
		try {
			OutputStreamWriter osw = new OutputStreamWriter(
					new FileOutputStream(file), "utf-8");
			for (int i = 0; i < cnames.size(); i++) {
				int[] rankpc_given_t = getRank(classid_pc_given_t[i]);
				int[] rankPc_given_t_times_pt_given_c = getRank(classid_pc_given_t_times_pt_given_c[i]);
				int[] rankcnt = getRankInt(classid_typecnts[i]);
				String cname = cnames.get(i);
				for (int j = 0; j < classid_typeids[i].size(); j++) {
					int tid = classid_typeids[i].get(j);
					String typename = tnames.get(tid);
					int cnt = classid_typecnts[i].get(j);
					int hererankcnt = rankcnt[j];
					double pc_given_t = classid_pc_given_t[i].get(j);
					int hererank_pc_given_t = rankpc_given_t[j];
					double Pc_given_t_times_pt_given_c = classid_pc_given_t_times_pt_given_c[i]
							.get(j);
					int hererankPc_given_t_times_pt_given_c = rankPc_given_t_times_pt_given_c[j];
					double pt_given_c = classid_pt_given_c[i].get(j);
					double pt_given_not_c = classid_pt_given_not_c[i].get(j);
					int which_big_pt_c_or_pt_not_c = pt_given_c>pt_given_not_c?1:0;
					osw.write(cname + "\t" + typename + "\t" + cnt + "\t"
							+ hererankcnt + "\t" + pc_given_t + "\t"
							+ hererank_pc_given_t + "\t"
							+ Pc_given_t_times_pt_given_c + "\t"
							+ hererankPc_given_t_times_pt_given_c + "\t"
							+pt_given_c+"\t"+pt_given_not_c+"\t"+which_big_pt_c_or_pt_not_c+"\n");
				}
			}
			osw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void printRandom(String file, int num){
		HashSet<Integer> set = new HashSet<Integer>();
		int max = cnames.size()-1;
		for(int i=0;i<num;i++){
			int a = (int)Math.round( Math.random()* max);
			if(!set.contains(a)){
				set.add(a);
			}
		}
		try {
			OutputStreamWriter osw = new OutputStreamWriter(
					new FileOutputStream(file), "utf-8");
			for (int i = 0; i < cnames.size(); i++) {
				if(!set.contains(i))continue;
				int[] rankpc_given_t = getRank(classid_pc_given_t[i]);
				int[] rankPc_given_t_times_pt_given_c = getRank(classid_pc_given_t_times_pt_given_c[i]);
				int[] rankcnt = getRankInt(classid_typecnts[i]);
				String cname = cnames.get(i);
				for (int j = 0; j < classid_typeids[i].size(); j++) {
					int tid = classid_typeids[i].get(j);
					String typename = tnames.get(tid);
					int cnt = classid_typecnts[i].get(j);
					int hererankcnt = rankcnt[j];
					double pc_given_t = classid_pc_given_t[i].get(j);
					int hererank_pc_given_t = rankpc_given_t[j];
					double Pc_given_t_times_pt_given_c = classid_pc_given_t_times_pt_given_c[i]
							.get(j);
					int hererankPc_given_t_times_pt_given_c = rankPc_given_t_times_pt_given_c[j];
					double pt_given_c = classid_pt_given_c[i].get(j);
					double pt_given_not_c = classid_pt_given_not_c[i].get(j);
					int which_big_pt_c_or_pt_not_c = pt_given_c>pt_given_not_c?1:0;
					osw.write(cname + "\t" + typename + "\t" + cnt + "\t"
							+ hererankcnt + "\t" + pc_given_t + "\t"
							+ hererank_pc_given_t + "\t"
							+ Pc_given_t_times_pt_given_c + "\t"
							+ hererankPc_given_t_times_pt_given_c + "\t"
							+pt_given_c+"\t"+pt_given_not_c+"\t"+which_big_pt_c_or_pt_not_c+"\n");
				}
			}
			osw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		
	}

	
}
